/*
 * -------------------------------------- 
 * FileName: 1_1.employee_manager.c 
 * Content:
 * 
 * Auther:  杨则瑞 
 * Encode:  utf-8 | CRLF                  
 * -------------------------------------- 
 */

#include<stdio.h>
#include<string.h>

#include<seq_list.h>


typedef struct employee_t
{

    // 唯一员工id
    char id[20]; 
    // 员工姓名
    char name[256];
    // 员工职务
    char position[512];
 
} employee_t;


// sqList异常处理，由于两个表都是同种数据结构，就用了一个变量
sqList_error_t app_erros;

//已辞职的员工
sqList_t archivedEmployees;

//现有员工
sqList_t employees;

//欢迎
const char motto[] = 
"====================================================================== \n"\
"      Task 1 :      Employee Manage System  (sequential list):         \n"\
"---------------------------------------------------------------------- \n"\
"    welcome! You can use \"help\" command to get helper docs           \n"\
"                                                                       \n"\
"                                                                       \n"\
"====================================================================== \n";

//帮助文档
const char helping[] = 
"======================================================================\n"
"add : \"add <id> <name> [discription]\"\n"
"   add a employee to currentEmployee list.\n"
"del : \"del <id> [-f(permanently)]\"\n"
"   del a employee from list, move it to Disinged employ list\n"
"       if \'-f\' is set, delete the entry permanently.\n"
"list : \"list [-a(show disigned)]\".\n"
"   list employee list.\n"
"show : \"show <id>\"\n"
"   print the name and discription of the entry with same id\n"
"quit : \"quit\".\n"
"   quit the programme\n"
"help : \"help\".\n"
"   print this page.\n"
"======================================================================\n";

static void cmd_list(const char *args);
static void cmd_quit(const char *);
static void cmd_add(const char * args);
static void cmd_query(const char * args);
static void cmd_help(const char * args);
static void cmd_delete(const char * args);

void init()
{
    printf("initing...\n");

    // 初始化数据结构
    app_erros = sqList_OK;
    sqList_init(&archivedEmployees, sizeof(employee_t), &app_erros);
    sqList_init(&employees, sizeof(employee_t), &app_erros);

    if(app_erros != sqList_OK)
    {
        printf("Encounter errors in initing database.\n");
        return;
    }

    printf(motto);
}




int running = 0;

int main(int argc, char * argv[])
{
    char cmd_buffer[1024];


    init();

    struct cmd_t {
        char command_name[20];
        void (*command)  (const char *);
    };

    struct cmd_t cmds[] = {
       {"list", cmd_list},
       {"add",  cmd_add},
       {"quit", cmd_quit},
       {"del", cmd_delete},
       {"show", cmd_query},
       {"help", cmd_help}
    };

    running = 1;
    while(running)
    {
        printf("\r>");
        fflush(stdout);

        //获取用户一行的输入
        fgets(cmd_buffer,1000,stdin);

        char ins[20];
        int offset;

        // 从用户输入的内容里找命令
        int all_len = strlen(cmd_buffer);
        sscanf(cmd_buffer,"%19s%n",ins,&offset);

        // 遍历所有命令，找到对应的，就执行
        unsigned char matched = 0;
        for(int i = 0; i < sizeof(cmds) / sizeof(struct cmd_t); ++ i)
        {
            if(0 == strcmp(cmds[i].command_name,ins) && all_len > offset)
            {
                cmds[i].command(cmd_buffer+offset);
                matched = 1;
            }
        }
        if(matched == 0)
        {
            printf("unrecongized command: %19s\n",ins);
        }
    }
    return 0;
}





static void cmd_list(const char *args)
{
    // 是否显示全部的 flag.
    unsigned char show_all_flag = 0;

    // 捕获参数，判断是否含有 'a'.
    char param[20];
    sscanf(args, "%19s", param);

    int n = strlen(param);
    for(int i = 0; i < n; ++ i)
    {
        if(param[i] == 'a')
        {
            show_all_flag = 1;
        }
    }

    // 列举当前员工列表
    printf("List of current employees, %u in total:\n", employees._len);
    for(int i = 0; i < employees._len; ++ i)
    {
        employee_t *p = ((employee_t *)sqList_get(&employees,i));
        printf("id:%s name:%s\n", p->id, p->name);
    }

    if(show_all_flag)
    {
        // 列举已辞职员工列表
        printf("List of disigned employees, %u in total:\n",  archivedEmployees._len);
        for(int i = 0; i < archivedEmployees._len; ++ i)
        {
            employee_t *p = ((employee_t *)sqList_get(&archivedEmployees,i));
            printf("id:%s name:%s\n", p->id, p->name);
        }
    }
}

static void cmd_quit(const char * _args)
{
    sqList_uninit(&archivedEmployees);
    sqList_uninit(&employees);

    running = 0;
}

static void cmd_add(const char * args)
{
    employee_t tmp;
    *tmp.position = '\0';
    
    int nums = sscanf(args,"%19s%255s%511s", &tmp.id, &tmp.name, &tmp.position);
    
    //参数不合法
    if(nums < 2)
    {
        printf("usage : \"add <id> <name> [discription]\".\n");
        return;
    }

    // 遍历员工
    for(int i = 0; i < employees._len; ++ i)
    {
        employee_t* itr = (employee_t*)sqList_get(&employees, i);
        if(0==strcmp(tmp.id,(itr ->id)))
        {
            printf("duplicate id (same as %s's). not added.\n", itr->name);
            return;
        }
    }

    // 遍历已经辞职的员工。注：员工虽然辞职了但是id不能冲突，除非强制删除。
    for(int i = 0; i < archivedEmployees._len; ++ i)
    {
        employee_t* itr = (employee_t*)sqList_get(&archivedEmployees, i);
        if(0==strcmp(tmp.id,(itr ->id)))
        {
            printf("duplicate id (same as %s(resigned)'s). not added.\n", itr->name);
            return;
        }
    }

    size_t idx = employees._len;
    employee_t* empl = (employee_t*) sqList_insertive_get(&employees, idx);
    memcpy(empl, &tmp, sizeof(employee_t));
}

static void cmd_delete(const char * args)
{
    unsigned char force_delete_flag = 0;

    char id[21];
    char param[21];

    int num = sscanf(args, "%20s%20s", id, param);

    //参数不合法
    if(num < 1)
    {
        printf("usage : \"del <id> [-f(fore delete)]\"\n");
        return;
    }

    if(num == 2)
    {
        int len = strlen(param);
        for(int i = 0; i < len; ++ i)
        {
            if(param[i] == 'f')
            {
                force_delete_flag = 1;
            }
        }
    }

    //遍历所有员工
    size_t idx = employees._len;
    for(int i = 0; i < idx; ++ i)
    {
        employee_t* itr = (employee_t*)sqList_get(&employees, i);
     
        // 匹配员工 id
        if(0==strcmp(id,(itr ->id)))
        {
            // 如果没有设置 -f 就把这个插入到辞职员工表里面。
            if(force_delete_flag == 0)
            {
                employee_t* newplace = (employee_t*)sqList_insertive_get(&archivedEmployees, archivedEmployees._len);
                if(newplace == NULL)
                {
                    printf("fatal: fail to move");
                    return;
                }
                memcpy(newplace,sqList_get(&employees, i),sizeof(employee_t));
            }

            sqList_erase(&employees,i);
            return;
        }
    }

    // 如果 -f 加上了，就会去从辞职员工列表里查找、删除。
    if(force_delete_flag)
    {
        idx = archivedEmployees._len;
        for(int i = 0; i < idx; ++ i)
        {
            employee_t* itr = (employee_t*)sqList_get(&archivedEmployees, i);
            if(0==strcmp(id,(itr ->id)))
            {
                sqList_erase(&archivedEmployees,i);
                return;
            }
        }
    }
    

    printf("not found.\n");

}

static void cmd_query(const char * args)
{
    char id[20];
    char param[20];

    int num = sscanf(args, "%20s%20s", id, param);

    // 参数非法
    if(num < 1)
    {
        printf("usage : \"show <id>\"\n");
        return;
    }
    

    //遍历所有员工
    size_t idx = employees._len;
    for(int i = 0; i < idx; ++ i)
    {
        employee_t* itr = (employee_t*)sqList_get(&employees, i);
        if(0==strcmp(id,(itr ->id)))
        {
            printf("name: %s\ndiscription: %s\n", itr->name, itr->position);
            return;
        }
    }

    idx = archivedEmployees._len;
    for(int i = 0; i < idx; ++ i)
    {
        employee_t* itr = (employee_t*)sqList_get(&archivedEmployees, i);
        if(0==strcmp(id,(itr ->id)))
        {
            printf("name: %s(disigned)\ndiscription: %s\n", itr->name, itr->position);
            return;
        }
    }

    printf("Not found.\n");
}

static void cmd_help(const char * _args)
{
    printf(helping);
    return;
}